package com.cy.pj.sys.service;

import com.cy.pj.common.exception.ServiceException;
import com.cy.pj.common.vo.PageObject;
import com.cy.pj.sys.entity.SysUser;
import com.cy.pj.sys.mapper.SysUserMapper;
import com.cy.pj.sys.mapper.SysUserRoleMapper;
import com.cy.pj.sys.vo.SysUserDeptVo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service
public class SysUserServiceImpl implements SysUserService{
    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Override
    public PageObject<SysUserDeptVo> findPageObjects(
            String username, Integer pageCurrent) {
        //1.对参数进行校验
        if(pageCurrent == null || pageCurrent < 1)
        throw new IllegalArgumentException("当前页码值无效");
        //2.查询总记录数并进行校验
        int rowCount = sysUserMapper.getRowCount(username);
        if(rowCount == 0)
        throw new ServiceException("没有找到对应的记录");
        //3.查询当前页记录
        int pageSize = 5;
        int startIndex = (pageCurrent - 1) * pageSize;
        List<SysUserDeptVo> records =
                sysUserMapper.findPageObjects(username, startIndex, pageSize);
        //4.对查询结果进行封装并返回
        return new PageObject<>(pageCurrent,pageSize,rowCount,records);
    }


    /**
     * 修改用户状态信息--此注解只能写在service层，写在controller层则报错
     * shrio框架通过@RequiresPermissions注解定义切入点，在这里表示
     * 访问此方法需要具备RequiresPermissions注解中的权限标识
     * 1.需要系统基于登录用户获取用户权限{"sys:user:update","sys:user:view"}
     * 2.当用户权限中包含@RequiresPermissions注解中定义的权限标识，
     * 就表示用户拥有访问这个方法的权限
     * 3.拥有权限时，则可以由shiro框架进行授权访问
     */
    @RequiresPermissions("sys:user:update")
    @Override
    @Transactional
    public int validById(Integer id, Integer valid) {
        //1.合法性验证
        if(id == null || id < 0)
        throw new IllegalArgumentException("参数不合法,id=" + id);
        if(valid != 1 && valid != 0)
        throw new IllegalArgumentException("参数不合法,valid=" + valid);
        //2.执行禁用或启用操作
        int rows = sysUserMapper.validById(id,valid);
        //3.判断结果,并返回
        if(rows == 0)
        throw new ServiceException("此记录可能已经不存在");
        return rows;
    }

    /**
     * 保存用户信息以及用户角色关系数据
     */
    @RequiresPermissions("sys:user:add")
    @Override
    @Transactional
    public int saveObject(SysUser entity, Integer[] roleIds) {
        //1.参数校验
        if(entity == null)
        throw new IllegalArgumentException("保存的对象不能为空");
        if(StringUtils.isEmpty(entity.getUsername()))
        throw new IllegalArgumentException("用户名不能空");
        if(StringUtils.isEmpty(entity.getPassword()))
        throw new IllegalArgumentException("密码不能为空");
        if(roleIds == null || roleIds.length == 0)
        throw new IllegalArgumentException("至少要为用户分配角色");
        //2.保存用户自身信息
        //2.1 对密码进行加密处理
        String source = entity.getPassword();
        String salt = UUID.randomUUID().toString();
        SimpleHash sh = new SimpleHash("MD5", source, salt, 1);
        //3.将信息存入到对象中
        entity.setSalt(salt);
        entity.setPassword(sh.toHex());
        int rows = sysUserMapper.insertObject(entity);
        //4.保存用户角色关系数据
        sysUserRoleMapper.insertObjects(entity.getId(), roleIds);
        //5.返回结果
        return rows;
    }

    @Override
    public Map<String, Object> findObjectById(Integer userId) {
        //1.合法性验证
        if(userId == null || userId <= 0)
            throw new IllegalArgumentException("id不合法,userId=" + userId);
        //2.业务查询
        SysUserDeptVo user = sysUserMapper.findObjectById(userId);
        if(user == null)
            throw new ServiceException("此用户已经不存在");
        List<Integer> roleIds = sysUserRoleMapper.findRoleIdsByUserId(userId);
        //3.封装数据
        Map<String,Object> map = new HashMap<>();
        map.put("user", user);
        map.put("roleIds",roleIds);
        return map;
    }

    @RequiresPermissions("sys:user:update")
    @Override
    @Transactional
    public int updateObject(SysUser entity, Integer[] roleIds) {
        //1.校验参数的有效性
        if(entity == null)
            throw new IllegalArgumentException("保存对象不能为空");
        if(StringUtils.isEmpty(entity.getUsername()))
            throw new IllegalArgumentException("用户名不能为空");
        if(roleIds == null || roleIds.length == 0)
            throw new IllegalArgumentException("必须指定角色");
        //2.更新用户自身信息
        int rows = sysUserMapper.updateObject(entity);
        //3.保存用户角色相关数据
        sysUserRoleMapper.deleteObjectsByUserId(entity.getId());
        sysUserRoleMapper.insertObjects(entity.getId(), roleIds);
        //4.返回结果
        return rows;
    }

    @Override
    public int updatePassword(String password,
                              String newPassword, String cfgPassword) {

        //1.判断新密码是否为空
        if(StringUtils.isEmpty(newPassword) && StringUtils.isEmpty(cfgPassword))
            throw new IllegalArgumentException("新密码不能为空");
        if(!newPassword.equals(cfgPassword))
            throw new IllegalArgumentException("新密码和确认密码必须相同");
        //2.判断原密码是否正确
        if(StringUtils.isEmpty(password))
            throw new IllegalArgumentException("原密码不能为空");
        //2.1获取登录用户
        SysUser user = (SysUser)SecurityUtils.getSubject().getPrincipal();
        SimpleHash md5 =
                new SimpleHash("MD5", password, user.getSalt(), 1);
        //3.判断原密码是否正确
        if(!user.getPassword().equals(md5.toHex()))
            throw new IllegalArgumentException("原密码不正确");
        //4.判断新密码和原密码是否相同
        if(password.equals(newPassword))
            throw new IllegalArgumentException("新密码与原密码相同");
        //5.将新密码加密处理
        String salt = UUID.randomUUID().toString();
        md5 = new SimpleHash("MD5",newPassword,salt,1);
        //6.将新密码和salt更新到数据库
        int rows = sysUserMapper.updatePassword(md5.toHex(), salt, user.getId());
        if(rows == 0)
            throw new ServiceException("修改失败");
        return rows;
    }
}
